# encoding=utf-8
import json
import datetime
import itertools
import copy
import os
import re
import urllib2
import urlparse

import bottle
import redis

import common


# connection = pymongo.Connection()
# db = connection.eleme

config_file = json.loads(file('../server.json').read())
redis_pool = redis.ConnectionPool(**config_file['redis'])
redis_db = redis.Redis(connection_pool=redis_pool)

# common


def order_split_group(all_order):
    all_split_order = [k.split('--') + [all_order[k]] for k in all_order]
    all_split_order.sort(key=lambda x: x[0])
    for o in all_split_order:
        o[2] = int(o[2])
    menu_names = list(set([(o[1], o[2]) for o in all_split_order]))
    user_names = list(set([o[0] for o in all_split_order]))

    order_group = itertools.groupby(all_split_order, key=lambda x: x[0])
    order_group_group = {k: {(i[1], i[2]): i[3] for i in v} for k, v in order_group}

    matrix = [[int(order_group_group[un].get(mn, 0)) for mn in menu_names] for un in user_names]
    return menu_names, user_names, matrix


def client_file_replace():
    name_data_dict = {root+'/'+f: file(root+'/'+f).read() for root, _, files in os.walk('../client/') for f in files}
    for js_var_name, js_var_data in config_file['client_replace'].iteritems():
        pattern = (ur'(var\s+' + js_var_name + u'\s+=\s+)(\'.*\'|\".*\")').encode('utf-8')
        repl = (ur'\1"%s"' % js_var_data).encode('utf-8')
        for filename, filedata in name_data_dict.iteritems():
            name_data_dict[filename] = re.sub(pattern, repl, filedata)

    for filename, filedata in name_data_dict.iteritems():
        file(filename, 'w').write(filedata)

#

@bottle.route("/api/py/add_menu", method="GET")
def get_menu():
    # request data
    params = bottle.request.params
    user_name = params['name']

    menu_list = json.loads(params['menu'])
    shop_url = urllib2.unquote(params['shop_url'])

    # inline data
    today_format = datetime.datetime.now().strftime('%Y%m%d')
    today_namespace = common.get_menu_namespace(today_format, shop_url)
    split_menu_namespace = common.get_split_menu_namespace(today_format, shop_url)
    shop_urls_namespace = common.get_shop_urls_namespace(today_format)
    if redis_db.hlen(split_menu_namespace):
        return bottle.abort("500", "page was locked")
    url_no_exist = redis_db.sadd(shop_urls_namespace, shop_url)
    if url_no_exist:
        spide_url = config_file['client_replace']['server_host']+'/api/js/ele_me_restaurant_spider'
        spide_url += '?url=' + params['shop_url']
        urllib2.urlopen(spide_url)
    for m in menu_list:
        m['name'] = m['name'].encode('utf-8')
        key = "%s--%s--%s" % (
            common.safe_encode(user_name), common.safe_encode(m['name']), common.safe_encode(m['unit']))
        redis_db.hincrby(today_namespace, key, m.get('amount', 0))
        if int(redis_db.hget(today_namespace, key)) <= 0:
            redis_db.hdel(today_namespace, key)
    urlpath = urlparse.urlparse(shop_url).path
    bottle.redirect("/order_list.html#shopdiv-" + urlpath[1:])


@bottle.route("/api/py/split_menu/show")
def split_menu():
    params = bottle.request.params

    today_format = datetime.datetime.now().strftime('%Y%m%d')
    shop_url = urllib2.unquote(params['shop_url'])

    namespace = common.get_split_menu_namespace(today_format, shop_url)
    split_discount_key = common.get_discount_key(today_format, shop_url)
    d = redis_db.hgetall(namespace)
    if not d:
        return ""
    discount_rate = float(redis_db.get(split_discount_key))

    group = [i[1] for i in sorted([(k, json.loads(v)) for k, v in d.iteritems()], key=lambda x: int(x[0]))]
    menu_names = list(set([tuple(m[0]) for l in group for m in l]))
    group_len_range = range(len(group))
    group_with_dict = [{tuple(obj[0]): obj[1] for obj in g} for g in group]
    matrix = [[group_with_dict[i].get(name_and_unit, 0) for name_and_unit in menu_names] for i in group_len_range]

    return json.dumps({'menu_names': menu_names,
                       'fuck_js': group_len_range,
                       'matrix': matrix,
                       'discount_rate': discount_rate})


@bottle.route("/api/py/split_menu/create")
def create_split_menu():
    params = bottle.request.params
    shop_url = urllib2.unquote(params['shop_url'])
    today_format = datetime.datetime.now().strftime('%Y%m%d')
    # ---------------------    在线支付XX减XX的关键字    -----------------------
    shop_info = json.loads(redis_db.hget('ele-shops', shop_url))
    discount = shop_info['discount']
    print discount
    # --------------------  起送价 --------------------------
    least_deliver = shop_info['least_deliver']
    # 满减优惠不能低于起送价
    discount = [(max(tup[0], least_deliver), tup[1]) for tup in discount]
    # --------------------------------------------------------------
    today_namespace = common.get_menu_namespace(today_format, shop_url)
    split_menu_namespace = common.get_split_menu_namespace(today_format, shop_url)
    split_discount_key = common.get_discount_key(today_format, shop_url)
    # suppose

    preferential = [d[0] for d in discount]

    if redis_db.hlen(split_menu_namespace):
        return ""
    else:
        all_order = redis_db.hgetall(today_namespace)
        menu_names, user_names, matrix = order_split_group(all_order)

        menu_amounts = [sum(int(line[i]) for line in matrix) for i in range(len(menu_names))]  # construct -> [amount]
        menu_amounts_dict = {menu_names[i]: sum(int(line[i]) for line in matrix) for i in range(len(menu_names))}
        # 本想用groupby 但itertools库的groupby各种BUG不敢用了
        menu_names_group_with_unit = {}  # construct -> {unit: [name] ...}
        menu_names_group_amounts = {}  # construct -> [(unit, amount) ...]

        for i in range(len(menu_names)):
            n, u = menu_names[i]
            if u not in menu_names_group_with_unit:
                menu_names_group_with_unit[u] = []
            if u not in menu_names_group_amounts:
                menu_names_group_amounts[u] = 0
            menu_names_group_with_unit[u].append(n)
            menu_names_group_amounts[u] += menu_amounts[i]

        # convert to  list
        # menu_names_group_with_unit = sorted(menu_names_group_with_unit.items(), key=lambda x: x[0], reverse=True)
        menu_names_group_amounts = sorted(menu_names_group_amounts.items(), key=lambda x: x[0], reverse=True)
        print 'unit_amount:', menu_names_group_amounts

        # split model

        # print 'ideal:', ideal_split_model
        # split to [[(unit, num) ...] ...]
        ideal_split_model = []
        surplus = copy.deepcopy(menu_names_group_amounts)
        _sum = common.arr_sum(surplus)
        split_list = []
        while 1:
            p = 0
            for _p in preferential:
                if _sum >= _p:
                    p = _p
                    ideal_split_model.append(_p)
                    break

            if not p:
                if not ideal_split_model:
                    split_list.append(surplus)
                else:
                    split_list[-1] = common.arr_push(split_list[-1], surplus)
                break

            f = common.close_to(p)
            near_arr = f(surplus)
            split_list.append(near_arr)
            surplus = common.arr_sub(surplus, near_arr)
            _sum = common.arr_sum(surplus)

        print 'split_list:', split_list
        #  calculate discount

        dict_discount = dict(discount)
        print split_list
        a = sum(common.arr_sum(s) for s in split_list)
        b = a - sum(dict_discount[i] for i in ideal_split_model)
        discount_rate = b / float(a)
        redis_db.set(split_discount_key, discount_rate)

        # split to [[((menu_name, menu_unit), num) ...] ...]
        surplus = copy.deepcopy(menu_amounts_dict)
        split_menu_list = []
        for sub_menu in split_list:
            menu_obj = []
            for unit, amount in sub_menu:
                __sur = amount
                for name in menu_names_group_with_unit[unit]:
                    __num = surplus[(name, unit)]
                    if __num >= __sur:
                        surplus[(name, unit)] -= __sur
                        menu_obj.append(((name, unit), __sur))
                        break
                    else:
                        __sur -= __num
                        surplus[(name, unit)] = 0
                        menu_obj.append(((name, unit), __num))
            split_menu_list.append(menu_obj)
    for i in range(len(split_menu_list)):
        redis_db.hset(split_menu_namespace, i, json.dumps(split_menu_list[i]))


@bottle.route("/api/py/split_menu/clean")
def clean_split_menu():
    params = bottle.request.params
    shop_url = urllib2.unquote(params['shop_url'])

    namespace = common.get_split_menu_namespace(datetime.datetime.now().strftime('%Y%m%d'), shop_url)
    redis_db.delete(namespace)
    return "true"


@bottle.route("/api/py/today_order_form")
def today_order_form():
    """
    redis data construct:
        user_name--menu_name--unit: amount
    """
    params = bottle.request.params
    shop_url = urllib2.unquote(params['shop_url'])

    today_namespace = common.get_menu_namespace(datetime.datetime.now().strftime('%Y%m%d'), shop_url)
    all_order = redis_db.hgetall(today_namespace)
    menu_names, user_names, matrix = order_split_group(all_order)
    return json.dumps({'menu_names': menu_names,
                       'user_names': user_names,
                       'matrix': matrix})

# TODO
@bottle.route("/api/py/today_shop_urls")
def today_shop_urls():
    time_format = common.get_shop_urls_namespace(datetime.datetime.now().strftime('%Y%m%d'))
    shop_urls = list(redis_db.sunion(time_format))
    shop_infos = [json.loads(info) if info else None
                  for info in redis_db.hmget('ele-shops', shop_urls)]
    print shop_infos

    shop_infos_add = [dict({'url': shop_urls[i]}, **shop_infos[i])
                      for i in range(len(shop_infos)) if shop_infos[i]]

    return json.dumps(list(shop_infos_add))


client_file_replace()
app = application = bottle.default_app()
if __name__ == '__main__':
    bottle.run(host='0.0.0.0', port=8888)



